#ifndef LOMVALUEFACTORYHH
#define LOMVALUEFACTORYHH
#include "lom-typedefs.hh"

namespace lom
{
    class LomValue;
    class ILomInstanceManager;
    
    class ILomValueFactory
    {
    public:
	virtual ~ILomValueFactory(){}
	virtual LomValue* create( EDataType type ) = 0;
	virtual void destroy( LomValue* value ) = 0;
    };
    
    typedef std::pair< TValueVector, TValueVector > TValueVectorPair;
    typedef std::vector< TValueVectorPair> TValueVectorPairVector;


    //Re-uses datatypes as much as possible
    class LomValueFactory : public ILomValueFactory
    {
	ILomInstanceManager* mgr;
	TValueVectorPairVector valueCache;
	
    public:
	LomValueFactory( ILomInstanceManager* _mgr = NULL);
	virtual ~LomValueFactory();
	void setup( ILomInstanceManager* _mgr );
	//Returns lom values that hand themselves
	virtual LomValue* create( EDataType type );
	virtual void destroy( LomValue* value );
	virtual void reset();
    };

    //Helper classes when using lom values with factories
    class LomValueAutoPtr
    {
	mutable LomValue* value;
	ILomValueFactory* factory;
    public:
	LomValueAutoPtr() : value( NULL ), factory( NULL ){}
	LomValueAutoPtr( const LomValueAutoPtr& other ) 
	    : value( other.value ), factory( other.factory ) {
	    other.value = NULL;
	}
	LomValueAutoPtr& operator=( const LomValueAutoPtr& other ) {
	    if ( &other == this )
		return *this;
	    if ( other.factory )
		factory = other.factory;
	    value = other.value;
	    other.value = NULL;
	    return *this;
	}
	LomValueAutoPtr( LomValue* _value, ILomValueFactory* _factory )
	    : value( _value ), factory( _factory ){}
	~LomValueAutoPtr() {
	    release();
	}
	void setFactory( ILomValueFactory* _factory ) {
	    factory = _factory;
	}
	void operator=( LomValue* _value ) {
	    if ( value != _value )
		release();
	    value = _value;
	}
	LomValue& operator->( ) { return *value; }
	const LomValue& operator->( ) const { return *value; }
	LomValue& operator*() { return *value; }
	const LomValue& operator*() const { return *value; }
	bool operator==( const LomValue* other ) const {
	    return value == other;
	}
	bool operator==( const LomValueAutoPtr& other ) const {
	    return value == other.value;
	}
    private:
	inline void release() {
	    if ( value )
		factory->destroy( value );
	    value = NULL;
	}
    };
}
#endif
